Module modules.stag

File name: stag.py Author: Martin Jůda Python Version: 3.7 Description: Module responsible for communication with Stag API

Expand source code
"""
    File name: stag.py
    Author: Martin Jůda
    Python Version: 3.7
    Description: Module responsible for communication with Stag API
"""

import requests

from modules.constants import STAG_AUTH, STAG_BASE_URL
from modules.errors import NoActiveStudyError, StagUnavailableError


class StagCommunicator:
    def get_active_studies(self, card_number):
        """Verify if active study exists for this card number and find student's ID

        Args:
            card_number (str): Card number

        Returns:
            list(dict): Detail about active studies and about student.

        Raises:
            StagUnavailableError: Connection to Stag API can not be established.
            NoActiveStudyError: No active study for this card number.
        """
        url = f"{STAG_BASE_URL}/student/getStudiaByCisloKarty"
        params = dict(cisloKarty=card_number, outputFormat="json")
        try:
            study_report = self._send_get_request(
                url=url, params=params, auth=STAG_AUTH
            )
        except requests.RequestException as err:
            raise StagUnavailableError() from err
        else:
            return self._parse_active_study(study_report)

    def get_completed_subjects_for_study(self, study, actual_year):
        """Get all completed subjects for selected study, skip subjects from actual year
        because they may not be completed yet.

        Args:
            study (dict): info about study program
            actual_year (datetime.year): Year for compare

        Returns:
            list(dict): List of completed subjects set

        """
        url = f"{STAG_BASE_URL}/predmety/getPredmetyByStudent"
        last_year = actual_year - 1
        completed_subjects = []

        params = dict(
            osCislo=study["osCislo"], outputFormat="json", semestr="%", rok="%"
        )
        try:
            response = self._send_get_request(url=url, params=params, auth=STAG_AUTH)
        except requests.RequestException as err:
            raise StagUnavailableError() from err
        else:
            subjects = response.get("predmetStudenta")
            if subjects:
                max_year = max([int(subject["rok"]) for subject in subjects])
                if max_year in [actual_year, last_year]:
                    completed_subjects = [
                        {
                            "subject_code": f"{subject['katedra']}/"
                            f"{subject['zkratka']}",
                            **subject,
                        }
                        for subject in subjects
                        if (
                            subject.get("statut") == "A" or subject.get("statut") == "B"
                        )
                        and int(subject["rok"]) != max_year
                    ]
                else:
                    completed_subjects = [
                        {
                            "subject_code": f"{subject['katedra']}/"
                            f"{subject['zkratka']}",
                            **subject,
                        }
                        for subject in subjects
                        if (
                            subject.get("statut") == "A" or subject.get("statut") == "B"
                        )
                    ]
        # return only unique subjects because student  could repeat the subject twice
        return list({s["subject_code"]: s for s in completed_subjects}.values())

    def get_study_codes_for_active_studies(self, active_studies):
        """Get study code for each active study

        Args:
            active_studies list(dict): active studies

        Returns:
            list(str): list of study codes
        """
        study_codes = []
        url = f"{STAG_BASE_URL}/student/getStudentInfo"
        for study in active_studies:
            params = dict(osCislo=study["osCislo"], outputFormat="json")
            try:
                response = self._send_get_request(
                    url=url, params=params, auth=STAG_AUTH
                )
            except requests.RequestException as err:
                raise StagUnavailableError() from err
            else:
                study_codes.append(response.get("kodSp"))
        return study_codes

    @staticmethod
    def _send_get_request(url, params=None, auth=None):
        """Send HTTP GET request to selected url

        Args:
            url (str): Destination URL
            params (dict): Query parameters
            auth (tuple): Basic HTTP authorization

        Returns:
            dict: data from json response
        """
        response = requests.get(url=url, params=params, auth=auth)
        response.raise_for_status()
        return response.json()

    @staticmethod
    def _parse_active_study(study_report):
        """Pick active studies from all of student's studies

        Args:
            study_report (dict): Info about student's studies from Stag

        Returns:
            dict: Active studies.

        Raises:
            NoActiveStudyError: No active study found.

        """
        active_studies = []
        studies = study_report.get("studentShort")
        if not studies:
            raise NoActiveStudyError()
        for study in studies:
            if study.get("stav") == "S":
                active_studies.append(study)
        if active_studies:
            return active_studies
        raise NoActiveStudyError()

Classes

class StagCommunicator
Expand source code
class StagCommunicator:
    def get_active_studies(self, card_number):
        """Verify if active study exists for this card number and find student's ID

        Args:
            card_number (str): Card number

        Returns:
            list(dict): Detail about active studies and about student.

        Raises:
            StagUnavailableError: Connection to Stag API can not be established.
            NoActiveStudyError: No active study for this card number.
        """
        url = f"{STAG_BASE_URL}/student/getStudiaByCisloKarty"
        params = dict(cisloKarty=card_number, outputFormat="json")
        try:
            study_report = self._send_get_request(
                url=url, params=params, auth=STAG_AUTH
            )
        except requests.RequestException as err:
            raise StagUnavailableError() from err
        else:
            return self._parse_active_study(study_report)

    def get_completed_subjects_for_study(self, study, actual_year):
        """Get all completed subjects for selected study, skip subjects from actual year
        because they may not be completed yet.

        Args:
            study (dict): info about study program
            actual_year (datetime.year): Year for compare

        Returns:
            list(dict): List of completed subjects set

        """
        url = f"{STAG_BASE_URL}/predmety/getPredmetyByStudent"
        last_year = actual_year - 1
        completed_subjects = []

        params = dict(
            osCislo=study["osCislo"], outputFormat="json", semestr="%", rok="%"
        )
        try:
            response = self._send_get_request(url=url, params=params, auth=STAG_AUTH)
        except requests.RequestException as err:
            raise StagUnavailableError() from err
        else:
            subjects = response.get("predmetStudenta")
            if subjects:
                max_year = max([int(subject["rok"]) for subject in subjects])
                if max_year in [actual_year, last_year]:
                    completed_subjects = [
                        {
                            "subject_code": f"{subject['katedra']}/"
                            f"{subject['zkratka']}",
                            **subject,
                        }
                        for subject in subjects
                        if (
                            subject.get("statut") == "A" or subject.get("statut") == "B"
                        )
                        and int(subject["rok"]) != max_year
                    ]
                else:
                    completed_subjects = [
                        {
                            "subject_code": f"{subject['katedra']}/"
                            f"{subject['zkratka']}",
                            **subject,
                        }
                        for subject in subjects
                        if (
                            subject.get("statut") == "A" or subject.get("statut") == "B"
                        )
                    ]
        # return only unique subjects because student  could repeat the subject twice
        return list({s["subject_code"]: s for s in completed_subjects}.values())

    def get_study_codes_for_active_studies(self, active_studies):
        """Get study code for each active study

        Args:
            active_studies list(dict): active studies

        Returns:
            list(str): list of study codes
        """
        study_codes = []
        url = f"{STAG_BASE_URL}/student/getStudentInfo"
        for study in active_studies:
            params = dict(osCislo=study["osCislo"], outputFormat="json")
            try:
                response = self._send_get_request(
                    url=url, params=params, auth=STAG_AUTH
                )
            except requests.RequestException as err:
                raise StagUnavailableError() from err
            else:
                study_codes.append(response.get("kodSp"))
        return study_codes

    @staticmethod
    def _send_get_request(url, params=None, auth=None):
        """Send HTTP GET request to selected url

        Args:
            url (str): Destination URL
            params (dict): Query parameters
            auth (tuple): Basic HTTP authorization

        Returns:
            dict: data from json response
        """
        response = requests.get(url=url, params=params, auth=auth)
        response.raise_for_status()
        return response.json()

    @staticmethod
    def _parse_active_study(study_report):
        """Pick active studies from all of student's studies

        Args:
            study_report (dict): Info about student's studies from Stag

        Returns:
            dict: Active studies.

        Raises:
            NoActiveStudyError: No active study found.

        """
        active_studies = []
        studies = study_report.get("studentShort")
        if not studies:
            raise NoActiveStudyError()
        for study in studies:
            if study.get("stav") == "S":
                active_studies.append(study)
        if active_studies:
            return active_studies
        raise NoActiveStudyError()

Methods

def get_active_studies(self, card_number)

Verify if active study exists for this card number and find student's ID

Args

card_number : str
Card number

Returns

list(dict): Detail about active studies and about student.

Raises

StagUnavailableError
Connection to Stag API can not be established.
NoActiveStudyError
No active study for this card number.
Expand source code
def get_active_studies(self, card_number):
    """Verify if active study exists for this card number and find student's ID

    Args:
        card_number (str): Card number

    Returns:
        list(dict): Detail about active studies and about student.

    Raises:
        StagUnavailableError: Connection to Stag API can not be established.
        NoActiveStudyError: No active study for this card number.
    """
    url = f"{STAG_BASE_URL}/student/getStudiaByCisloKarty"
    params = dict(cisloKarty=card_number, outputFormat="json")
    try:
        study_report = self._send_get_request(
            url=url, params=params, auth=STAG_AUTH
        )
    except requests.RequestException as err:
        raise StagUnavailableError() from err
    else:
        return self._parse_active_study(study_report)
def get_completed_subjects_for_study(self, study, actual_year)

Get all completed subjects for selected study, skip subjects from actual year because they may not be completed yet.

Args

study : dict
info about study program
actual_year : datetime.year
Year for compare

Returns

list(dict): List of completed subjects set

Expand source code
def get_completed_subjects_for_study(self, study, actual_year):
    """Get all completed subjects for selected study, skip subjects from actual year
    because they may not be completed yet.

    Args:
        study (dict): info about study program
        actual_year (datetime.year): Year for compare

    Returns:
        list(dict): List of completed subjects set

    """
    url = f"{STAG_BASE_URL}/predmety/getPredmetyByStudent"
    last_year = actual_year - 1
    completed_subjects = []

    params = dict(
        osCislo=study["osCislo"], outputFormat="json", semestr="%", rok="%"
    )
    try:
        response = self._send_get_request(url=url, params=params, auth=STAG_AUTH)
    except requests.RequestException as err:
        raise StagUnavailableError() from err
    else:
        subjects = response.get("predmetStudenta")
        if subjects:
            max_year = max([int(subject["rok"]) for subject in subjects])
            if max_year in [actual_year, last_year]:
                completed_subjects = [
                    {
                        "subject_code": f"{subject['katedra']}/"
                        f"{subject['zkratka']}",
                        **subject,
                    }
                    for subject in subjects
                    if (
                        subject.get("statut") == "A" or subject.get("statut") == "B"
                    )
                    and int(subject["rok"]) != max_year
                ]
            else:
                completed_subjects = [
                    {
                        "subject_code": f"{subject['katedra']}/"
                        f"{subject['zkratka']}",
                        **subject,
                    }
                    for subject in subjects
                    if (
                        subject.get("statut") == "A" or subject.get("statut") == "B"
                    )
                ]
    # return only unique subjects because student  could repeat the subject twice
    return list({s["subject_code"]: s for s in completed_subjects}.values())
def get_study_codes_for_active_studies(self, active_studies)

Get study code for each active study

Args

active_studies list(dict): active studies

Returns

list(str): list of study codes

Expand source code
def get_study_codes_for_active_studies(self, active_studies):
    """Get study code for each active study

    Args:
        active_studies list(dict): active studies

    Returns:
        list(str): list of study codes
    """
    study_codes = []
    url = f"{STAG_BASE_URL}/student/getStudentInfo"
    for study in active_studies:
        params = dict(osCislo=study["osCislo"], outputFormat="json")
        try:
            response = self._send_get_request(
                url=url, params=params, auth=STAG_AUTH
            )
        except requests.RequestException as err:
            raise StagUnavailableError() from err
        else:
            study_codes.append(response.get("kodSp"))
    return study_codes